﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;

namespace WpfApp1
{
    public partial class MainWindow : Window
    {
        private UIElement _draggingElement = null;
        private Point _dragStartPoint;
        private Point _elementStartPoint;

        public MainWindow()
        {
            InitializeComponent();
            UpdateConnection();
        }

        private void TextBoxContainer_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            _draggingElement = sender as UIElement;
            if (_draggingElement == null) return;

            _draggingElement.CaptureMouse();
            _dragStartPoint = e.GetPosition(this);
            _elementStartPoint = new Point(
                Canvas.GetLeft(_draggingElement),
                Canvas.GetTop(_draggingElement)
            );

            // 提升被拖动元素的Z轴顺序，确保在最上层
            Canvas.SetZIndex(_draggingElement, 10);

            e.Handled = true;
        }

        private void TextBoxContainer_MouseMove(object sender, MouseEventArgs e)
        {
            if (_draggingElement == null || e.LeftButton != MouseButtonState.Pressed)
                return;

            Point currentPoint = e.GetPosition(this);
            double deltaX = currentPoint.X - _dragStartPoint.X;
            double deltaY = currentPoint.Y - _dragStartPoint.Y;

            // 更新元素位置
            Canvas.SetLeft(_draggingElement, _elementStartPoint.X + deltaX);
            Canvas.SetTop(_draggingElement, _elementStartPoint.Y + deltaY);

            UpdateConnection();
        }

        private void TextBoxContainer_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (_draggingElement != null)
            {
                _draggingElement.ReleaseMouseCapture();
                _draggingElement = null;

                // 恢复元素的Z轴顺序
                Canvas.SetZIndex(TextBox1Container, 0);
                Canvas.SetZIndex(TextBox2Container, 0);
            }
        }

        private void UpdateConnection()
        {
            // 获取两个锚点的位置
            Point startPoint = GetAnchorPosition(Anchor1);
            Point endPoint = GetAnchorPosition(Anchor2);

            // 计算避障路径
            PathGeometry pathGeometry = CalculateAvoidObstaclePath(startPoint, endPoint);
            ConnectionPath.Data = pathGeometry;
        }

        private Point GetAnchorPosition(Ellipse anchor)
        {
            // 获取锚点相对于Canvas的位置
            return anchor.TranslatePoint(new Point(anchor.Width / 2, anchor.Height / 2), MainCanvas);
        }

        private PathGeometry CalculateAvoidObstaclePath(Point start, Point end)
        {
            PathGeometry geometry = new PathGeometry();
            PathFigure figure = new PathFigure { StartPoint = start };

            // 检查连线是否会穿过障碍物
            if (IsLineIntersectingObstacle(start, end))
            {
                // 计算障碍物边界
                Rect obstacleRect = new Rect(
                    Canvas.GetLeft(Obstacle),
                    Canvas.GetTop(Obstacle),
                    Obstacle.Width,
                    Obstacle.Height
                );

                // 计算避障路径
                PointCollection pathPoints = CalculateAvoidancePoints(start, end, obstacleRect);

                // 添加线段到路径
                foreach (Point point in pathPoints)
                {
                    figure.Segments.Add(new LineSegment(point, true));
                }
            }
            else
            {
                // 直接连接两点
                figure.Segments.Add(new LineSegment(end, true));
            }

            geometry.Figures.Add(figure);
            return geometry;
        }

        private bool IsLineIntersectingObstacle(Point start, Point end)
        {
            // 计算障碍物边界
            Rect obstacleRect = new Rect(
                Canvas.GetLeft(Obstacle),
                Canvas.GetTop(Obstacle),
                Obstacle.Width,
                Obstacle.Height
            );

            // 检查线段是否与障碍物矩形相交
            return LineIntersectsRect(start, end, obstacleRect);
        }

        private bool LineIntersectsRect(Point p1, Point p2, Rect rect)
        {
            // 检查线段的两个端点是否在矩形内
            if (rect.Contains(p1) || rect.Contains(p2))
                return true;

            // 检查线段是否与矩形的四条边相交
            Point rectTopLeft = new Point(rect.Left, rect.Top);
            Point rectTopRight = new Point(rect.Right, rect.Top);
            Point rectBottomLeft = new Point(rect.Left, rect.Bottom);
            Point rectBottomRight = new Point(rect.Right, rect.Bottom);

            return LineIntersectsLine(p1, p2, rectTopLeft, rectTopRight) ||
                   LineIntersectsLine(p1, p2, rectTopRight, rectBottomRight) ||
                   LineIntersectsLine(p1, p2, rectBottomRight, rectBottomLeft) ||
                   LineIntersectsLine(p1, p2, rectBottomLeft, rectTopLeft);
        }

        private bool LineIntersectsLine(Point a1, Point a2, Point b1, Point b2)
        {
            double ua = ((b2.X - b1.X) * (a1.Y - b1.Y) - (b2.Y - b1.Y) * (a1.X - b1.X)) /
                        ((b2.Y - b1.Y) * (a2.X - a1.X) - (b2.X - b1.X) * (a2.Y - a1.Y));

            double ub = ((a2.X - a1.X) * (a1.Y - b1.Y) - (a2.Y - a1.Y) * (a1.X - b1.X)) /
                        ((b2.Y - b1.Y) * (a2.X - a1.X) - (b2.X - b1.X) * (a2.Y - a1.Y));

            return ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1;
        }

        private PointCollection CalculateAvoidancePoints(Point start, Point end, Rect obstacle)
        {
            PointCollection points = new PointCollection();

            // 确定从障碍物左侧还是右侧绕行
            bool avoidRight = ShouldAvoidRight(start, end, obstacle);
            double offset = 30; // 避障偏移距离

            // 计算中间点
            double midX = avoidRight ? obstacle.Right + offset : obstacle.Left - offset;
            double midY = (start.Y + end.Y) / 2;

            // 创建三段式折线避障路径
            points.Add(new Point(midX, start.Y));     // 第一点：横向偏移
            points.Add(new Point(midX, midY));        // 第二点：纵向偏移
            points.Add(new Point(midX, end.Y));       // 第三点：横向偏移
            points.Add(end);                          // 终点

            return points;
        }

        private bool ShouldAvoidRight(Point start, Point end, Rect obstacle)
        {
            // 计算起点和终点的中点
            double midX = (start.X + end.X) / 2;

            // 如果中点在障碍物右侧，从右侧绕行；否则从左侧绕行
            return midX > obstacle.Left + obstacle.Width / 2;
        }
    }
}